(()=>{
    function unicodeStrToUtf8Byte(str) {
      var bytes = new Array();
      for (var i = 0; i < str.length; i++) {
        var c = str.charCodeAt(i);
        var s = parseInt(c).toString(2);
        if(c >= parseInt("000080",16) && c <= parseInt("0007FF",16)){
          var af = "";
          for(var j = 0; j < (11 - s.length); j++){
            af += "0";
          }
          af += s;
          var n1 = parseInt("110" + af.substring(0,5),2);
          var n2 = parseInt("110" + af.substring(5),2);
          if(n1 > 127) n1 -= 256;
          if(n2 > 127) n2 -= 256;
          bytes.push(n1);
          bytes.push(n2);
        }else if(c >= parseInt("000800",16) && c <= parseInt("00FFFF",16)){
          var af = "";
          for(var j = 0; j < (16 - s.length); j++){
            af += "0";
          }
          af += s;
          var n1 = parseInt("1110" + af.substring(0,4),2);
          var n2 = parseInt("10" + af.substring(4,10),2);
          var n3 = parseInt("10" + af.substring(10),2);
          if(n1 > 127) n1 -= 256;
          if(n2 > 127) n2 -= 256;
          if(n3 > 127) n3 -= 256;
          bytes.push(n1);
          bytes.push(n2);
          bytes.push(n3);
        }else if(c >= parseInt("010000",16) && c <= parseInt("10FFFF",16)){
          var af = "";
          for(var j = 0; j < (21 - s.length); j++){
            af += "0";
          }
          af += s;
          var n1 = parseInt("11110" + af.substring(0,3),2);
          var n2 = parseInt("10" + af.substring(3,9),2);
          var n3 = parseInt("10" + af.substring(9,15),2);
          var n4 = parseInt("10" + af.substring(15),2);
          if(n1 > 127) n1 -= 256;
          if(n2 > 127) n2 -= 256;
          if(n3 > 127) n3 -= 256;
          if(n4 > 127) n4 -= 256;
          bytes.push(n1);
          bytes.push(n2);
          bytes.push(n3);
          bytes.push(n4);
        }else{
          bytes.push(c & 0xff);
        }
      }
      return bytes;
    
    }
    
    
    function utf8ByteToUnicodeStr(utf8Bytes) {
      var unicodeStr = "";
      for (var pos = 0; pos < utf8Bytes.length;) {
        var flag = utf8Bytes[pos];
        var unicode = 0;
        if ((flag >>> 7) === 0) {
          unicodeStr += String.fromCharCode(utf8Bytes[pos]);
          pos += 1;
    
        } else if ((flag & 0xFC) === 0xFC) {
          unicode = (utf8Bytes[pos] & 0x3) << 30;
          unicode |= (utf8Bytes[pos + 1] & 0x3F) << 24;
          unicode |= (utf8Bytes[pos + 2] & 0x3F) << 18;
          unicode |= (utf8Bytes[pos + 3] & 0x3F) << 12;
          unicode |= (utf8Bytes[pos + 4] & 0x3F) << 6;
          unicode |= (utf8Bytes[pos + 5] & 0x3F);
          unicodeStr += String.fromCodePoint(unicode);
          pos += 6;
    
        } else if ((flag & 0xF8) === 0xF8) {
          unicode = (utf8Bytes[pos] & 0x7) << 24;
          unicode |= (utf8Bytes[pos + 1] & 0x3F) << 18;
          unicode |= (utf8Bytes[pos + 2] & 0x3F) << 12;
          unicode |= (utf8Bytes[pos + 3] & 0x3F) << 6;
          unicode |= (utf8Bytes[pos + 4] & 0x3F);
          unicodeStr += String.fromCodePoint(unicode);
          pos += 5;
    
        } else if ((flag & 0xF0) === 0xF0) {
          unicode = (utf8Bytes[pos] & 0xF) << 18;
          unicode |= (utf8Bytes[pos + 1] & 0x3F) << 12;
          unicode |= (utf8Bytes[pos + 2] & 0x3F) << 6;
          unicode |= (utf8Bytes[pos + 3] & 0x3F);
          unicodeStr += String.fromCodePoint(unicode);
          pos += 4;
    
        } else if ((flag & 0xE0) === 0xE0) {
          unicode = (utf8Bytes[pos] & 0x1F) << 12;;
          unicode |= (utf8Bytes[pos + 1] & 0x3F) << 6;
          unicode |= (utf8Bytes[pos + 2] & 0x3F);
          unicodeStr += String.fromCharCode(unicode);
          pos += 3;
    
        } else if ((flag & 0xC0) === 0xC0) { //110
          unicode = (utf8Bytes[pos] & 0x3F) << 6;
          unicode |= (utf8Bytes[pos + 1] & 0x3F);
          unicodeStr += String.fromCharCode(unicode);
          pos += 2;
    
        } else {
          unicodeStr += String.fromCharCode(utf8Bytes[pos]);
          pos += 1;
        }
      }
      return unicodeStr;
    }
    
    function byte2Hex(byteData){
      const chs = "0123456789ABCDEF";
      const byteLen = byteData.length;
      const hexArr = new Array();
      for(let i = 0;i < byteLen;i++){
        const byteH = (byteData[i]&0xF0) >> 4;
        const byteL = byteData[i]&0x0F;
        hexArr.push(chs[byteH]);
        hexArr.push(chs[byteL]);
      }
      return hexArr.join('');
    }
    
    function hex2Byte(hex){
      const chs = "0123456789ABCDEF";
      const loopLen = hex.length;
      const byteArr = new Array();
      for(let i = 0; i < loopLen;i = i+2){
        const byteH = chs.indexOf(hex[i]);
        const byteL = chs.indexOf(hex[i + 1]);
        let byteData = (byteH << 4)|byteL; 
        if(byteData > 127){
          byteData -= 256;
        }
        byteArr.push(byteData);
      }
      return byteArr;
    }

    const str2Hex = function(str){
      const byteData = unicodeStrToUtf8Byte(str);
      const hexStr = byte2Hex(byteData);
      return hexStr;
    };

    const hex2Str = function(hex){
      const byteData = hex2Byte(hex);
      //console.log(byteData);
      const strData = utf8ByteToUnicodeStr(byteData);
      return strData;
    };

    let isInApp = false;
    if(window.YljShellApp != undefined && YljShellApp) {
      try{
        const result = YljShellApp.inApp();
        const json = JSON.parse(hex2Str(result));
        isInApp = json.inApp;
        window.YljAdSdk.envCheckFinish = true;
      }catch(e){}
    }

    // let isInIOS = false;
    // try{
    //   const runtimeEventName = "runtimeCallbackEvent_" + new Date().getTime();
    //   const runtimeCheckFun = function(e) {
    //     const dataObj = e.detail;
    //     let params = new Object();
    //     if(dataObj.hasOwnProperty('ps')) {
    //         params = JSON.parse(hex2Str(dataObj['ps']));
    //         if(params.hasOwnProperty('isIOS')) {
    //           isInIOS = params.isIOS;
    //         }
    //     }

    //     window.removeEventListener(runtimeEventName, runtimeCheckFun);
    //   }
    //   window.addEventListener(runtimeEventName, runtimeCheckFun);
    //   window.webkit.messageHandlers.jsToOcWithPrams.postMessage({eventName:runtimeEventName, name:"runtime"});
    // }catch(e){}

    //判断访问终端
    const appBrowserInfo={
      versions: function() { 
          var u = navigator.userAgent, app = navigator.appVersion; 
          return {//移动终端浏览器版本信息
                  trident: u.indexOf('Trident') > -1, //IE内核
                  presto: u.indexOf('Presto') > -1, //opera内核
                  webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
                  gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
                  mobile: !!u.match(/AppleWebKit.*Mobile.*/)||!!u.match(/AppleWebKit/), //是否为移动终端
                  ios: !!u.match(/(i[^;]+;)( U;)? CPU.+Mac OS X/), //ios终端
                  android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
                  iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者QQHD浏览器
                  iPad: u.indexOf('iPad') > -1, //是否iPad
                  webApp: u.indexOf('Safari') == -1, //是否web应该程序，没有头部与底部
                  inShell:u.indexOf('0da051aa5cd470e2f0fecd1b70126646') > -1 
          };
      }(),
      language:(navigator.browserLanguage || navigator.language).toLowerCase()
  }

    let isInIOS = (appBrowserInfo.versions.iPhone || appBrowserInfo.versions.iPad) && appBrowserInfo.versions.inShell;

    /**
     * sdk广告调用
     */
     if(window.YljAdSdk == undefined) {
        // window.addEventListener("unload", function() {
        //     YljShellApp.pageDestory();
        // }); 
        window.YljAdSdk = new Object();
        window.YljAdSdk.callbackMap = new Object();
        const callbackEventName = "yljSDKCallbackEvent_" + new Date().getTime();

          window.YljAdSdk.info = function(tag, message) {

            console.log(`${tag} => ${message}`);
            if(isInApp) {
              const hexStr = str2Hex(message);
              YljShellApp.info(tag, hexStr);
            }else if(isInIOS) {
              const hexStr = str2Hex(message);
              window.webkit.messageHandlers.jsToOcWithPrams.postMessage({name:"info", tag:tag, message, hexStr});
            }

          }

          // 创建事件
          // let myEvent = new CustomEvent("yljSDKCallbackEvent", );window.dispatchEvent(myEvent);

          // 添加适当的事件监听器
          window.addEventListener(callbackEventName, e => {
            // alert(`yljSDKCallbackEvent事件触发，是 ${e.detail['callbackId']} 触发。`);
            const dataObj = e.detail;

            let params = new Object();
            if(dataObj.hasOwnProperty('ps')) {
                params = JSON.parse(hex2Str(dataObj['ps']));
            }

            const callbackId = dataObj['callbackId'];

            // alert(`name : ${dataObj['name']}, callbackId : ${callbackId}, ps : ${params}`);

            const callback = window.YljAdSdk.callbackMap[callbackId];

            const name = dataObj['name'];
            if(callback) {
                callback(dataObj['name'], params);
                if('onLoadFailed' == name || 'onShowFailed' == name || 'onAdClosed' == name) {
                    window.YljAdSdk.callbackMap[callbackId] = undefined;
                }
            }

          });


          window.YljAdSdk.osType = function(){

            if(isInApp){
              return "android";
            }else if(isInIOS){
              return "ios";
            }else{
              return "unkown";
            }
          }

          window.YljAdSdk.inApp = function() {
            return isInApp || isInIOS;
          };

          //初始化
          window.YljAdSdk.init = function(cpid, appId, channel, debug) {
            if(isInApp) {
              YljShellApp.sdkInit(cpid, appId, channel, debug);
            }else if(isInIOS) {
              window.webkit.messageHandlers.jsToOcWithPrams.postMessage({name:"sdkInit", cpid : cpid, appId : appId, channel:channel, debug:debug});
            }
          };

          //开屏
          window.YljAdSdk.splashAd = function(appAdId, callback, timeout){
            const callbackId = new Date().getTime() + "splash";
            window.YljAdSdk.callbackMap[callbackId] = callback;
            if(isInApp){
              YljShellApp.showSplashAd(callbackEventName, appAdId, callbackId, timeout);
            }else if(isInIOS){
              window.webkit.messageHandlers.jsToOcWithPrams.postMessage({name:"splashAd", eventName : callbackEventName, appAdId : appAdId, callbackId:callbackId, timeout:timeout});
            }
            
          }

          //插屏
          window.YljAdSdk.interstitialAd = function(appAdId, callback){
            const callbackId = new Date().getTime() + "insert";
            window.YljAdSdk.callbackMap[callbackId] = callback;
            if(isInApp){
              YljShellApp.showInterstitialAd(callbackEventName, appAdId, callbackId);
            }else if(isInIOS){
              window.webkit.messageHandlers.jsToOcWithPrams.postMessage({name:"insertAd", eventName : callbackEventName, appAdId : appAdId, callbackId:callbackId});
            }
            
          };

          //全屏视频
          window.YljAdSdk.fullScreenAd = function(appAdId, callback){
            const callbackId = new Date().getTime() + "fullscreen";
            window.YljAdSdk.callbackMap[callbackId] = callback;
            if(isInApp){
              YljShellApp.fullScreenAd(callbackEventName, appAdId, callbackId);
            }else if(isInIOS){
              window.webkit.messageHandlers.jsToOcWithPrams.postMessage({name:"fullScreenAd", eventName : callbackEventName, appAdId : appAdId, callbackId:callbackId});
            }
            
          };

          //激励视频
          window.YljAdSdk.rewardAd = function(appAdId, callback, userId, extInfo){
            const callbackId = new Date().getTime() + "reward";
            window.YljAdSdk.callbackMap[callbackId] = callback;
            if(isInApp){
              YljShellApp.rewardAd(callbackEventName, appAdId, callbackId, userId, extInfo);
            }else if(isInIOS){
              window.webkit.messageHandlers.jsToOcWithPrams.postMessage({name:"rewardAd", eventName : callbackEventName, appAdId : appAdId, callbackId : callbackId, userId : userId, extInfo : extInfo});
            }
            
          };

          window.YljAdSdk.loadPlugins = function(){
            if(window.AppExt == undefined || !AppExt.nativeMethod("inApp")){
              return ;
            }

            if(window.plus == undefined) {
              window.plus = window.AppExt.plus;
            }else {
              const originPlus = new Object();
              Object.assign(originPlus, window.plus);
              window.plus = originPlus;

              Object.assign(window.plus, window.AppExt.plus);
            }
            window.AppExt.plus = undefined;

            if(window.uni == undefined) {
              window.uni = window.AppExt.uni;
            }else {
              const originUni = new Object();
              Object.assign(originUni, window.uni);
              window.uni = originUni;

              Object.assign(window.uni, window.AppExt.uni);
            }
            window.AppExt.uni = undefined;
          };

    }

    /**
     * 壳应用功能扩展
     */
    if(window.AppExt == undefined) {
        window.AppExt = new Object();
        window.AppExt.callbackMap = new Object();
        const extCallbackEventName = "extCallbackEventName_" + new Date().getTime();

        // 添加适当的事件监听器
        window.addEventListener(extCallbackEventName, e => {
          // alert(`yljSDKCallbackEvent事件触发，是 ${e.detail['callbackId']} 触发。`);
          const dataObj = e.detail;

          let params = new Object();
          if(dataObj.hasOwnProperty('ps')) {
              params = JSON.parse(hex2Str(dataObj['ps']));
          }

          const callbackId = dataObj['callbackId'];
          const callback = window.AppExt.callbackMap[callbackId];
          if(callback) {
              callback(params);
              window.AppExt.callbackMap[callbackId] = undefined;
          }

        });

        /**
         * 当参数超过指定长度，分片传参
         */
        const paramsSliceWhenLen = 2000000;
        // const paramsSliceWhenLen = 3;
        const sliceData = function(dataStr){
          const subMaxLen = paramsSliceWhenLen;
          const dataLen = dataStr.length;
          const loopCount = dataLen / subMaxLen;
          
          let dataCacheId = null;
          for(let i = 0;i < loopCount;i++){
              const start = i*subMaxLen;
              const end = Math.min((i + 1)*subMaxLen, dataStr.length);
              // console.log(`第${i}次，str : ${dataStr.substring(start, end)}`)
              dataCacheId = YljShellApp.dataSlice(dataCacheId, dataStr.substring(start, end));
          }

          return dataCacheId;
      }

      window.AppExt.nativeMethod = function(name, params, callback) {
          if("inApp" == name) {
            // if(isInIOS) {
            //   console.log("is in ios");
            // }
            return isInApp || isInIOS;
          }
          const argInfo = new Object();
          argInfo.name = name;

          if(params != undefined && params) {
            const psStr = str2Hex(JSON.stringify(params));
            if(psStr.length > paramsSliceWhenLen) {
              argInfo.dataCacheId = sliceData(psStr);
            } else {
              argInfo.params = psStr;
            }
          }

          if(callback != undefined && callback) {
            const callbackId = new Date().getTime() + "name";
            window.AppExt.callbackMap[callbackId] = callback;
            argInfo.callbackId = callbackId;
          }
        
          YljShellApp.callNativeMethod(extCallbackEventName, JSON.stringify(argInfo));
      }

    }

    if(window.AppExt.plus == undefined) {
      window.AppExt.plus = new Object();
      window.AppExt.plus.navigator = new Object();
      window.AppExt.plus.navigator.hideSystemNavigation = function(){
        window.AppExt.nativeMethod("hideSystemNavigation");
      }

      window.AppExt.plus.screen = new Object();
      window.AppExt.plus.screen.lockOrientation = function(orientation){
        window.AppExt.nativeMethod("lockOrientation", orientation);
      }

      window.AppExt.plus.runtime = new Object();
      window.AppExt.plus.runtime.appid = "property.appid";
      window.AppExt.plus.runtime.getProperty = function(propertyName, callback) {
        window.AppExt.nativeMethod("getProperty", propertyName, callback);
      }

    }

    if(window.AppExt.uni == undefined) {
        window.AppExt.uni = new Object();

        window.AppExt.uni.chooseImage = function(ps){
          window.AppExt.nativeMethod("chooseImage", ps, function(res){
            if(ps.complete != undefined) {
              ps.complete();
            }
  
            //data.tempFilePaths
            if(res.success) {
              if(ps.success != undefined) {
                ps.success(res.data);
              }
              return ;
            }
  
            //err.errMsg
            if(ps.fail != undefined) {
              ps.fail(res.err);
            }
  
          });
  
        }
  
        window.AppExt.uni.openSetting = function(ps){
          window.AppExt.nativeMethod("openSetting");
        }
  
        window.AppExt.uni.uploadFile = function(ps) {
            window.AppExt.nativeMethod("uploadFile", ps, function(res){
              if(ps.complete != undefined) {
                ps.complete();
              }
    
              if(res.success) {
                if(ps.success != undefined) {
                  ps.success(res.data);
                }
                return ;
              }
    
              if(ps.fail != undefined) {
                ps.fail(res.data);
              }
    
            });
        }

        window.AppExt.uni.saveImageToPhotosAlbum = function(ps) {
          window.AppExt.nativeMethod("saveImageToPhotosAlbum", ps, function(res){
            if(ps.complete != undefined) {
              ps.complete();
            }

            const success = res.success;
            res.success = undefined;
            if(success) {
              if(ps.success != undefined) {
                ps.success();
              }
              return ;
            }

            if(ps.fail != undefined) {
              ps.fail(res);
            }

          });
      }
      

    }

  })()